package com.mssh.login.util;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import javax.crypto.Cipher;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Base64;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import com.mssh.entity.exception.SecretException;

/**
 * Created with IntelliJ IDEA.
 *
 * @Author: 熳殊沙华
 * @Date: 2023/09/20/8:58
 * @Description:
 */
public class RsaUtil {

    private static Logger logger = LogManager.getLogger(RsaUtil.class);

    //加密算法
    private static final String ALGO_NAME = "RSA";

    //算法默认为RSA/NONE/PKCS1Padding，未验证
    public static final String CIPHER_ALGORITHM = "RSA/ECB/PKCS1Padding";

    //RSA密钥长度必须是64的倍数，在512~65536之间。默认是1024
    public static final int KEY_SIZE = 2048;

    //加密请求返回对象的公钥
    private static String PUBLIC_KEY = PropertiesUtil.getPublicKey();

    //解密请求返回对象的私钥（放在配置文件中）
    private static String PRIVATE_KEY = PropertiesUtil.getPrivateKey();

    /**
     * 注意只能生成一次
     * @return 私钥公钥密钥对
     */
    public static Map<String,String> generateKeyPairs() throws SecretException {
        try {
            KeyPairGenerator generator = KeyPairGenerator.getInstance(ALGO_NAME);
            generator.initialize(KEY_SIZE);  //rsa长度
            KeyPair keyPair = generator.generateKeyPair();
            RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
            RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
            Map<String, String> map = new ConcurrentHashMap<>();
            String id = UUID.randomUUID().toString().replaceAll("-", "");
            map.put("id", id);
            map.put("public_key", Base64.getEncoder().encodeToString(publicKey.getEncoded()));
            map.put("private_key",Base64.getEncoder().encodeToString(privateKey.getEncoded()));
            return map;
        } catch (Exception e) {
            e.printStackTrace();
            throw new SecretException("生成RSA钥公钥密钥对异常");
        }
    }

    /**
     * 公钥加密算法
     * @param needEncodeText 需要加密的字符串)
     */
    public static String encrypt(String needEncodeText) throws SecretException {
        try {
            byte[] publicKeyBytes = Base64.getDecoder().decode(PUBLIC_KEY.getBytes());

            PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(publicKeyBytes);
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            PublicKey publicKey = keyFactory.generatePublic(keySpec);

            // 使用私钥进行加密
            Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.ENCRYPT_MODE, publicKey);

            //将需要加密的字串转字节码
            byte[] bytes = needEncodeText.getBytes();
            // 加密
            byte[] resultBytes = cipher.doFinal(bytes);
            //转base64(不清楚是否需要判断为空)
            return Base64.getEncoder().encodeToString(resultBytes);
        } catch (Exception e) {
            e.printStackTrace();
            throw new SecretException("RSA加密异常");
        }
    }

    /**
     * 私钥解密算法
     * @param needDecodeText 需要解密的字符串
     */
    public static String desEncrypt(String needDecodeText) throws SecretException {
        try {
            Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
            //将字符串转PublicKey对象
            // bytes 为base64处理后的字节码，所以要先base64Encoder一下
            byte[] data = Base64.getDecoder().decode(PRIVATE_KEY.getBytes());
            PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(data);
            KeyFactory fact = KeyFactory.getInstance(ALGO_NAME);
            PrivateKey privateKey1 = fact.generatePrivate(spec);
            //初始化加密工具
            cipher.init(Cipher.DECRYPT_MODE, privateKey1);
            //将需要加密的字串转字节码
            //base64转byte
            byte[] bytes = Base64.getDecoder().decode(needDecodeText.getBytes());
            // 解密
            byte[] resultBytes = cipher.doFinal(bytes);
            return resultBytes == null ? null : new String(resultBytes);
        } catch (Exception e) {
            e.printStackTrace();
            throw new SecretException("RSA解密异常");
        }
    }
}
